package com.zjw.jwdatacenter.handler;


import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.SocketAddress;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * NettyWebSocketServer2的websocket连接及数据处理器。
 *
 * @author ZJW
 * @email 1192935956@qq.com
 * @date 2025/8/9 0:11
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class SignalWebSocketHandler2 extends SimpleChannelInboundHandler<WebSocketFrame> {

    // 存储所有已连接的 QMT 客户端 Channel
    public static final CopyOnWriteArraySet<Channel> CLIENTS = new CopyOnWriteArraySet<>();

    @Resource
    private ObjectMapper objectMapper; // 用于 JSON 序列化

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        CLIENTS.add(channel);
//        System.out.println("QMT Client connected: " + channel.remoteAddress());
        log.info("ws客户端[{}]连接成功！", channel.remoteAddress());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        SocketAddress remoteAddress = channel.remoteAddress();

        CLIENTS.remove(channel);
        log.info("ws客户端[{}]断开连接！", remoteAddress);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msgFrame) throws Exception {
        Channel channel = ctx.channel();
        SocketAddress remoteAddress = channel.remoteAddress();

        if (msgFrame instanceof TextWebSocketFrame) {
            String msgText = ((TextWebSocketFrame) msgFrame).text();
            log.info("接收到ws客户端[{}]的文本消息：{}", remoteAddress, msgText);

            // 解析 JSON
            try {
                JSONObject jsonObject = JSONUtil.parseObj(msgText);
                String type = jsonObject.getStr("type");

                if ("ping".equals(type)) {
                    // 收到客户端应用层心跳
                    log.info("接收到客户端[{}]发送过来的ping包：{}", remoteAddress, msgText);

                    // 回复 pong
                    String pongMsg = "{\"type\": \"pong\", \"timestamp\": " + System.currentTimeMillis() + "}";
                    ctx.writeAndFlush(new TextWebSocketFrame(pongMsg));
                    log.info("给客户端[{}]回复pong包：{}", remoteAddress, pongMsg);
                    return; // 处理完心跳，不再往下传递
                } else if ("pong".equals(type)) { //接收到客户端回复的心跳pong包
                    log.info("接收到客户端[{}]发送过来的pong包：{}", remoteAddress, msgText);
                } else if ("flash".equals(type)) {
                    log.info("接收到客户端[{}]发送过来的flash报文：{}", remoteAddress, msgText);
                } else {
                    log.info("接收到的消息类型{}暂不支持处理！msgText: {}", type, msgText);
                }

            } catch (Exception e) {
                log.error("Parse message error", e);
            }
        } else if (msgFrame instanceof BinaryWebSocketFrame) { //二进制消息

        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        Channel channel = ctx.channel();
        SocketAddress remoteAddress = channel.remoteAddress();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
//            if (event.state() == IdleState.WRITER_IDLE) {
            if (event.state() == IdleState.ALL_IDLE) { //超过指定时长(如30秒)既没有读也没有写，则向该客户端发送心跳包
                // 写超时，意味着服务端很久没向客户端发消息了
                // 我们可以发送一个应用层心跳消息 (例如 JSON)
                String heartbeatMsg = "{\"type\": \"ping\", \"timestamp\": " + System.currentTimeMillis() + "}";
                TextWebSocketFrame frame = new TextWebSocketFrame(heartbeatMsg);
                ctx.writeAndFlush(frame);
                log.info("给ws客户端[{}]发送ping包: {}", remoteAddress, heartbeatMsg);
            }
            // 通常我们更关心读超时 (客户端是否还活着)
            else if (event.state() == IdleState.READER_IDLE) {
                // 读超时，意味着客户端很久没发消息了 (包括 Ping)
                log.warn("超过60秒仍未收到来自ws客户端[{}]的消息，将其连接断开！", remoteAddress);
                // 可以选择发送一个 Ping 消息 (应用层) 或直接关闭连接
                ctx.close();
            }
        } else if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            // 当 WebSocket 握手完成时触发
            WebSocketServerProtocolHandler.HandshakeComplete handshake =
                    (WebSocketServerProtocolHandler.HandshakeComplete) evt;
            log.info("ws客户端[{}]握手完成 - URI: {}, Headers: {}", remoteAddress, handshake.requestUri(), handshake.requestHeaders());
            // 这里可以记录新客户端连接
        }

        super.userEventTriggered(ctx, evt);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();

        log.error("e: {}", cause.getMessage());
    }

    // 提供给其他组件（如Controller）调用，向所有QMT客户端广播信号
    public static void broadcastSignal(Object signal) {
        String jsonSignal;
        try {
            jsonSignal = new ObjectMapper().writeValueAsString(signal);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        log.info("jsonSignal: {}", jsonSignal);

        log.info("CLIENTS.size: {}", CLIENTS.size());
        for (Channel client : CLIENTS) {
            log.info("client: {}", client);
            if (client.isActive()) {
                client.writeAndFlush(new TextWebSocketFrame(jsonSignal));
            }
        }
//        System.out.println("Broadcasted signal to " + CLIENTS.size() + " QMT clients.");
        log.info("向{}个web ws客户端发送报文数据：{}", CLIENTS.size(), jsonSignal);
    }

    // 提供给其他组件（如Controller）调用，向所有QMT客户端广播信号
    public static void broadcastStrSignal(String strMsg) {
        log.info("strMsg: {}", strMsg);

        log.info("CLIENTS.size: {}", CLIENTS.size());
        for (Channel client : CLIENTS) {
            log.info("client: {}", client);
            if (client.isActive()) {
                client.writeAndFlush(new TextWebSocketFrame(strMsg));
            }
        }
//        System.out.println("Broadcasted signal to " + CLIENTS.size() + " QMT clients.");
        log.info("向{}个web ws客户端发送报文数据：{}", CLIENTS.size(), strMsg);
    }
}
